package dev.ece.suit.multisample;

import dev.ece.core.cells.model.base.FboUI;
import dev.ece.core.cells.model.base.SquareUI;
import dev.ece.core.engine.LoaderFlush;
import dev.ece.core.engine.LoaderQueue;
import dev.ece.core.sprite.Component;
import dev.ece.core.texture.FBO;
import dev.ece.util.tools.Camera;
import dev.ece.util.tools.Projection;
import dev.ece.util.tools.Screen;

/**
 * @author 潜行的青衣
 * @see
 */
public class MultiSampleComponent extends Component<Float, SquareUI<Float>> {

	/**
	 * 
	 */
	private static final long serialVersionUID = -8736130224184716524L;
	
	private MultiSampleShader multiSampleShader;
	
	private FBO multiSampleFBO;
	
	private Camera camera = new Camera();
	
	private Projection projection;
	
	private Screen screen;
	
	public MultiSampleComponent(MultiSampleShader multiSampleShader, int width, int height, int samples) throws Exception {
		this(new FboUI(width, height), multiSampleShader, FBO.newInstance(samples, width, height));
	}
	
	/**
	 * @param model
	 */
	public MultiSampleComponent(SquareUI<Float> model, MultiSampleShader multiSampleShader, FBO multiSampleFBO) {
		super(model);
		this.multiSampleShader = multiSampleShader;
		this.multiSampleFBO = multiSampleFBO;
		this.camera.setPosition(0, 0, 2f);
		this.screen = new Screen(multiSampleFBO.getWidth(), multiSampleFBO.getHeight());
		this.projection = new Projection().set2DScreen(screen);
		this.initialize();
	}

	public void begin() {
		multiSampleFBO.begin();
	}
	
	public void render() {
		if(this.isVisible() && this.isInitialized()) {
			this.screen.glViewPort();
			this.projection.glProjection2D();
			this.camera.lookAt();
			this.render(camera);
		}
	}
	
	@Override
	public void onRender(Camera camera) {
		this.multiSampleShader.glUseProgram();
		this.multiSampleShader.glModelViewProjectMatrix();
		this.multiSampleShader.glMultiSample(multiSampleFBO.getSamples());
		this.multiSampleShader.glTexture(multiSampleFBO.getTexture());
		super.onRender(camera);
	}
	
	public void setScreen(Screen screen) {
		LoaderQueue.push((LoaderFlush flush) -> {
			boolean isVisible = MultiSampleComponent.this.isVisible();
			FboUI ui = new FboUI(screen.getWidth(), screen.getHeight());
			flush.finish();
			MultiSampleComponent.this.setVisible(false);
			MultiSampleComponent.this.getUi().destroy();
			MultiSampleComponent.this.setUi(ui);
			MultiSampleComponent.this.screen = new Screen(screen.getWidth(), screen.getHeight());
			MultiSampleComponent.this.projection.set2DScreen(MultiSampleComponent.this.screen);
			MultiSampleComponent.this.setInitialized(false);
			MultiSampleComponent.this.setVisible(isVisible);
		});
	}
	
	public Screen getScreen() {
		return screen;
	}
	
	public FBO getMultiSampleFBO() {
		return multiSampleFBO;
	}

	@Override
	public float getWidth() {
		return this.getUi().getWidth();
	}

	@Override
	public float getHeight() {
		return this.getUi().getHeight();
	}

	@Override
	public void destroy() {
		super.destroy();
		multiSampleFBO.destroy();
		multiSampleFBO = null;
	}

}
